import { Task, Project } from '../domain/index';
import * as _ from 'lodash';
import { createSelector } from '@ngrx/store';
import { TaskActionTypes, TaskActions } from '../actions/task.action';
import { ProjectActionTypes, ProjectActions } from '../actions/projects.action';

export interface State {
    ids: string[];
    entities: { [id: string]: Task };
}

const initialState: State = {
    ids: [],
    entities: {}
};

const addTask = (state, action) => {
    const taskList = action.payload;
    // 如果存在该taskList 则不添加
    if (state.entities[taskList.id]) {
        return state;
    }
    // 如果不存在 则在 ids 中添加 taskList.id
    const ids = [...state.ids, taskList.id];
    // 在entities 中添加项目
    const entities = { ...state.entities, [taskList.id]: taskList };
    return { ids, entities };
};

const updateTask = (state, action) => {
    const taskList = action.payload;
    // 替换
    const entities = { ...state, [taskList.id]: taskList };
    return { ...state, entities };
};
const delTask = (state, action) => {
    const taskList = action.payload;
    console.log('a', state.ids);
    const newIds = state.ids.filter(id => id !== taskList.id);
    const stateEntities = state.entities;
    const newEntities = newIds.reduce((entities, id: string) => ({ ...entities, [id]: stateEntities[id] }), {});
    return { ids: newIds, entities: newEntities };
};
// 加载新数据， 如果存在则不添加，如果不存在则添加进去，方便进行分页
const loadTask = (state, action) => {
    const task = action.payload; // 这里返回的是个数组
    const inComingIds = task.map(p => p.id); // 获取传进来的所有id
    const newIds = _.difference(inComingIds, state.ids); // 获取两个数组的超集
    // 获取一个新的字典(对象) keyBy: 列表对象中的id 最为新对象的key 对象为值
    const inComingEntities = _.chain(task)
        .keyBy('id')
        .mapValues(o => o)
        .value();
    const newEntities = newIds.reduce((entities, id: string) => ({ ...entities, [id]: inComingEntities[id] }), {});
    return {
        ids: [...state.ids, ...newIds],
        entities: { ...state.entities, ...newEntities }
    };
};


const moveAllTask = (state, action) => {
    const tasks = <Task[]>action.payload;
    const updateEntities = tasks.reduce((entities, task) => ({ ...entities, [task.id]: task }), {});
    return {
        ...state,
        entities: { ...state, ...updateEntities }
    };
};

const delByPrj = (state, action) => {
    const project = <Project>action.payload;
    const taskListIds = project.taskLists;
    const remainingIds = state.ids
        .filter(id => taskListIds.indexOf(state.entities[id].taskListId) === -1);
    const newEntities = remainingIds.reduce((entities, id) => ({ ...entities, [id]: state.entities[id] }), {});
    return {
        ids: [...remainingIds],
        entities: newEntities
    };
};

export function reducer(state = initialState, action: TaskActions | ProjectActions): State {
    switch (action.type) {
        case TaskActionTypes.ADD_SUCCESS: {
            return addTask(state, action);
        }
        case TaskActionTypes.DELETE_SUCCESS: {
            return delTask(state, action);
        }
        case TaskActionTypes.COMPLETE_SUCCESS:
        case TaskActionTypes.MOVE_SUCCESS:
        case TaskActionTypes.UPDATE_SUCCESS: {
            return updateTask(state, action);
        }
        case TaskActionTypes.LOAD_SUCCESS: {
            return loadTask(state, action);
        }
        case TaskActionTypes.MOVE_ALL_SUCCESS: {
            return moveAllTask(state, action);
        }
        case ProjectActionTypes.DELETE_SUCCESS: {
            return delByPrj(state, action);
        }
        default: {
            return state;
        }
    }
}

export const getIds = (state: State) => state.ids;
export const getEntities = (state: State) => state.entities;

export const getTasks = createSelector(getIds, getEntities, (ids, entities) => {
    return ids.map(key => entities[key]);
});
